package com.shelpe.services.sinbad.controller;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.shelpe.services.sinbad.dao.RptCreativeMapper;
import com.shelpe.services.sinbad.entity.jpa.Adgroup;
import com.shelpe.services.sinbad.entity.jpa.Creative;
import com.shelpe.services.sinbad.entity.jpa.CreativeLog;
import com.shelpe.services.sinbad.entity.jpa.CreativesError;
import com.shelpe.services.sinbad.entity.jpa.ProductImages;
import com.shelpe.services.sinbad.entity.jpa.User;
import com.shelpe.services.sinbad.entity.jpa.vo.CreativeVo;
import com.shelpe.services.sinbad.model.RptCreative;
import com.shelpe.services.sinbad.model.RptCreativeExample;
import com.shelpe.services.sinbad.model.RptCreativeExample.Criteria;
import com.shelpe.services.sinbad.repository.jpa.AdgroupRepository;
import com.shelpe.services.sinbad.repository.jpa.CreativeLogRepository;
import com.shelpe.services.sinbad.repository.jpa.CreativeRepository;
import com.shelpe.services.sinbad.repository.jpa.CreativesErrorRepository;
import com.shelpe.services.sinbad.repository.jpa.ProductImageRepository;
import com.shelpe.services.sinbad.repository.jpa.UserRepository;
import com.shelpe.services.sinbad.service.simbaproxy.CreativeClient;
import com.shelpe.services.sinbad.service.simbaproxy.SimbaProxyBaseDto;
import com.shelpe.services.sinbad.service.simbaproxy.CreativeClient.GetCreativeResponse;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
@RequestMapping("/sinbadservice")
@Api(value = "创意相关的API", consumes = "application/json", produces = "application/json")
public class CreativeController {

	static SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd");

	@Autowired
	private RptCreativeMapper rptCreativeMapper;
	@Autowired
	private AdgroupRepository adgroupRepository;
	@Autowired
	private CreativeRepository creativeRepository;
	@Autowired
	private CreativeClient creativeClient;
	@Autowired
	private CreativeLogRepository creativeLogRepository;
	@Autowired
	private ObjectMapper objectMapper;
	@Autowired
	private ProductImageRepository productImageRepository;
	@Autowired
	private UserRepository userRepository;
	@Autowired
	private CreativesErrorRepository creativesErrorRepository;

	@ApiOperation(value = "创意的同步")
	@RequestMapping(method = RequestMethod.GET, path = "/adgroups/{adgroup_id}/creatives")
	@ResponseBody
	public CreativeDto fetchCreative(@PathVariable("adgroup_id") long adgroupID) {
		Adgroup adgroup = this.adgroupRepository.findOne(adgroupID);
		Assert.notNull(adgroup, "adgroup_not_found");

		Map<Long, Creative> creativeMap = new HashMap<Long, Creative>();
		List<Creative> creatives = this.creativeRepository.findByAdgroupID(adgroupID);
		if (creatives != null && creatives.size() > 0) {
			for (Creative creative : creatives) {
				creativeMap.put(creative.getAutoID(), creative);
			}
		}
		List<CreativeLog> creativeLogs = this.creativeLogRepository.findByAdgroupID(adgroupID);
		Map<Long, CreativeLog> creativeLogMap = new HashMap<Long, CreativeLog>();
		if (creativeLogs != null && creativeLogs.size() > 0) {
			for (CreativeLog creativeLog : creativeLogs) {
				creativeLogMap.put(creativeLog.getCreativeID(), creativeLog);
			}
		}
		List<Creative> pos = new ArrayList<Creative>();
		List<CreativeLog> logs = new ArrayList<CreativeLog>();
		GetCreativeResponse cRes = this.creativeClient.findCreatives(adgroup.getNick(), adgroupID);
		if (cRes != null && cRes.getRes() != null && cRes.getRes().getDataList() != null
				&& cRes.getRes().getDataList().getCreatives() != null) {
			for (CreativeClient.CreativeDto creativeDto : cRes.getRes().getDataList().getCreatives()) {
				log.debug("fetch creative from taobao: {},>>>{}", creativeDto, cRes);
				Creative po = new Creative();
				if (!creativeMap.containsKey(creativeDto.getCreativeId())) {
					po.from(creativeDto, adgroup.getUserID(), adgroup.getCampaignID());
					pos.add(po);
				}
				
				if (!creativeLogMap.containsKey(po.getAutoID())) {
					CreativeVo creatVo = new CreativeVo();
					BeanUtils.copyProperties(po, creatVo);
					creatVo.setCreativeNewTitle(po.getTitle());
					CreativeLog cpo = new CreativeLog();
					cpo.from(po);
					cpo.setAction(CreativeLog.Action.MANUAL_ADD);
					
					if (adgroup.getDriveType() != null && adgroup.getDriveType().getValue() != 0) {
						cpo.setAction(CreativeLog.Action.AUTO_ADD);
					}
					
					try {
						cpo.setNote(this.objectMapper.writer().writeValueAsString(creatVo));
					} catch (JsonProcessingException e) {
						log.error("JsonProcessingException: {}", e);
						cpo.setNote("");
					}
					logs.add(cpo);
				}
			}
		}
		this.creativeRepository.save(pos);
		log.debug("finish to create creatives as sync: {} ", pos);
		this.creativeLogRepository.save(logs);
		log.debug("sync create creative CreativeLog: {}", logs);

		if (cRes != null && cRes.getError() != null) {
			CreativesError error = new CreativesError();
			error.setAdgroupID(adgroupID);
			error.setCreateTime(new Date());
			error.setStep("create_adgroup_second");
			try {
				error.setNote(objectMapper.writeValueAsString(cRes.getError()));
			} catch (JsonProcessingException e) {
				log.error("JsonProcessingException:{}", e);
				error.setNote("");
			}
			this.creativesErrorRepository.save(error);
			log.error("fail to create adgroup as sync: {}", "(原因为" + cRes.getError().getSubMessage() + ")");
		}

		CreativeDto dto = new CreativeDto();
		dto.setCreatives(new ArrayList<CreativeTemplete>());
		for (Creative po : pos) {
			CreativeTemplete templete = new CreativeTemplete();
			templete.setCreativeID(po.getAutoID());
			templete.setTitle(po.getTitle());
			templete.setUrl(po.getImage());
			dto.getCreatives().add(templete);
		}

		return dto;
	}

	@ApiOperation(value = "创意的查看")
	@RequestMapping(method = RequestMethod.GET, path = "/creatives/{adgroup_id}")
	@ResponseBody
	public CreativeDto findCreative(@PathVariable("adgroup_id") long adgroupID,
			@RequestParam(required = false, name = "days", defaultValue = "0") int days,
			@RequestParam(required = false, name = "device", defaultValue = "all") String device,
			@RequestParam(required = false, name = "start_date") String startDate,
			@RequestParam(required = false, name = "end_date") String endDate) {
		CreativeDto dto = new CreativeDto();

		Adgroup adgroup = this.adgroupRepository.findOne(adgroupID);
		Assert.notNull(adgroup, "adgroup_not_exist");
		dto.setProductID(adgroup.getProductID());
		User user = this.userRepository.findOne(adgroup.getUserID());
		Assert.notNull(user, "user_not_found");
		List<ProductImages> images = new ArrayList<ProductImages>();
		if (user.getUserType() == 2) {
			ProductImages image = new ProductImages();
			image.setUrl(adgroup.getProductUrl());
			image.setPosition(0);
			image.setImageId(0L);
			images.add(image);
		} else {
			images = this.productImageRepository.findByProductID(adgroup.getProductID());
			Assert.notNull(images, "images_not_exist");
		}

		dto.setCreativeUrls(new ArrayList<CreativeUrl>());
		for (ProductImages image : images) {
			CreativeUrl url = new CreativeUrl();
			if (image.getPosition() == 0) {
				url.setOriginal(true);
			}
			url.setPosition(image.getPosition());
			url.setUrl(image.getUrl());
			url.setUrlID(image.getImageId());
			dto.getCreativeUrls().add(url);
		}

		List<Creative> creatives = this.creativeRepository.findByAdgroupID(adgroupID);
		if (creatives == null || creatives.size() == 0) {
			dto.setCreatives(new ArrayList<CreativeTemplete>());
			return dto;
		}

		dto.setCreatives(new ArrayList<CreativeTemplete>());
		for (Creative creative : creatives) {
			CreativeTemplete templete = new CreativeTemplete();
			templete.setCreativeID(creative.getAutoID());
			templete.setTitle(creative.getTitle());
			templete.setUrl(creative.getImage());
			templete.setEffectMetric(this.summariesMetric(creative.getAutoID(), days, device, startDate, endDate));
			dto.getCreatives().add(templete);
		}
		log.debug("finish find creatives:{}", dto);
		return dto;
	}

	@ApiOperation(value = "创意的删除")
	@RequestMapping(method = RequestMethod.DELETE, path = "/creatives/{creative_id}")
	@ResponseBody
	public Response deleteCreative(@PathVariable("creative_id") long creativeID) {
		Response res = new Response();
		Creative creative = this.creativeRepository.findOne(creativeID);
		Assert.notNull(creative, "creative_not_exist");
		CreativeClient.DeleteCreativeResponse tbRes = this.creativeClient.deleteCreatives(creative.getNick(),
				creativeID);
		if (tbRes != null && tbRes.getRes() != null && tbRes.getRes().getCreative() != null) {
			this.creativeRepository.delete(creative);
			CreativeLog po = new CreativeLog();
			BeanUtils.copyProperties(creative, po);
			po.setAdgroupID(creative.getAdgroupID());
			po.setCreativeID(creative.getAutoID());
			po.setUpdatedTime(new Date());
			po.setAction(CreativeLog.Action.MANUAL_DEL);
			CreativeVo creatVo = new CreativeVo();
			creatVo.setCreativeOldTitle(creative.getTitle());
			try {
				po.setNote(this.objectMapper.writer().writeValueAsString(creatVo));
			} catch (JsonProcessingException e) {
				log.error("JsonProcessingException: {}", e);
				po.setNote("");
			}
			this.creativeLogRepository.save(po);
			res.setStatus(true);
		}

		if (tbRes != null && tbRes.getError() != null) {
			res.setError(tbRes.getError());
		}
		log.debug("finish delete creatives:{}", res);
		return res;
	}

	@Data
	public static class Response {
		private boolean status;
		private SimbaProxyBaseDto.Error error;
	}

	@Data
	public static class CreativeDto {
		@JsonProperty("product_id")
		private long productID;
		@JsonProperty("creative_urls")
		private List<CreativeUrl> creativeUrls;
		private List<CreativeTemplete> creatives;
	}

	@Data
	public static class CreativeTemplete {
		@JsonProperty("creative_id")
		private long creativeID;
		private String url;
		private String title;
		@JsonProperty("effect_metric")
		private EffectMetricDto effectMetric;
	}

	@Data
	public static class CreativeUrl {
		private int position;
		@JsonProperty("is_original")
		private boolean original;
		@JsonProperty("url_id")
		private long urlID;
		private String url;
	}

	/**
	 * 趋势图数据 .以日期分组
	 * 
	 * @param creativeId
	 * @return
	 */
	@ApiOperation(value = "创意的效果数据趋势")
	@RequestMapping(method = RequestMethod.GET, path = "/creatives/{creative_id}/reports/trend")
	public @ResponseBody List<EffectMetricDto> reportsTrend(@PathVariable("creative_id") Long creativeId,
			@RequestParam(required = false, name = "days", defaultValue = "0") int days,
			@RequestParam(required = false, name = "device", defaultValue = "all") String device,
			@RequestParam(required = false, name = "start_date") String startDate,
			@RequestParam(required = false, name = "end_date") String endDate) {
		log.info("reportsTrend creativeId:{} days:{} device:{} startDate:{} endDate:{}", creativeId, days, device,
				startDate, endDate);
		RptCreativeExample example = new RptCreativeExample();
		Criteria criteria = example.createCriteria();
		criteria.andCreativeIdEqualTo(creativeId);
		if ("pc".equals(device)) {
			criteria.andSourceBetween((byte) 1, (byte) 2);
		} else if ("mobile".equals(device)) {
			criteria.andSourceBetween((byte) 4, (byte) 5);
		} else {
			List<Byte> list = new ArrayList<Byte>();
			list.add((byte) 1);
			list.add((byte) 2);
			list.add((byte) 4);
			list.add((byte) 5);
			criteria.andSourceIn(list);
		}
		Date yesterday = DateUtils.addDays(DateUtils.truncate(new Date(), Calendar.DATE), -1);
		Date start = yesterday;
		Date end = yesterday;
		if (startDate != null) {
			try {
				start = SDF.parse(startDate);
				if (endDate != null) {
					end = SDF.parse(endDate);
				}
			} catch (ParseException e) {
				log.error("CreativeController reportsTrend:{}", e.getMessage());
			}
		} else if (days > 0) {
			start = DateUtils.addDays(yesterday, -days + 1);
		}
		criteria.andDateBetween(start, end);
		List<RptCreative> rpts = rptCreativeMapper.selectReportsTrendByDate(example);

		List<EffectMetricDto> dtos = new ArrayList<EffectMetricDto>();
		if (rpts != null) {
			for (RptCreative rpt : rpts) {
				EffectMetricDto dto = new EffectMetricDto();
				dto.from(rpt);
				dtos.add(dto);
			}
		}
		return dtos;
	}

	@ApiOperation(value = "创意的效果数据摘要")
	@RequestMapping(method = RequestMethod.GET, path = "/creatives/{creative_id}/summaries/metric")
	public @ResponseBody EffectMetricDto summariesMetric(@PathVariable("creative_id") Long creativeId,
			@RequestParam(required = false, name = "days", defaultValue = "0") int days,
			@RequestParam(required = false, name = "device", defaultValue = "all") String device,
			@RequestParam(required = false, name = "start_date") String startDate,
			@RequestParam(required = false, name = "end_date") String endDate) {
		log.info("reportsTrend creativeId:{} days:{} device:{} startDate:{} endDate:{}", creativeId, days, device,
				startDate, endDate);
		RptCreativeExample example = new RptCreativeExample();
		Criteria criteria = example.createCriteria();
		criteria.andCreativeIdEqualTo(creativeId);
		if ("pc".equals(device)) {
			criteria.andSourceBetween((byte) 1, (byte) 2);
		} else if ("mobile".equals(device)) {
			criteria.andSourceBetween((byte) 4, (byte) 5);
		} else {
			List<Byte> list = new ArrayList<Byte>();
			list.add((byte) 1);
			list.add((byte) 2);
			list.add((byte) 4);
			list.add((byte) 5);
			criteria.andSourceIn(list);
		}
		Date yesterday = DateUtils.addDays(DateUtils.truncate(new Date(), Calendar.DATE), -1);
		Date start = yesterday;
		Date end = yesterday;
		if (startDate != null) {
			try {
				start = SDF.parse(startDate);
				if (endDate != null) {
					end = SDF.parse(endDate);
				}
			} catch (ParseException e) {
				log.error("CreativeController reportsTrend:{}", e.getMessage());
			}
		} else if (days > 0) {
			start = DateUtils.addDays(yesterday, -days + 1);
		}
		criteria.andDateBetween(start, end);
		RptCreative rpt = rptCreativeMapper.sumByCondition(example);

		EffectMetricDto dto = new EffectMetricDto();
		dto.from(rpt);
		return dto;
	}
}
